跳到主要内容

SVN 的基本使用

SVN 是什么?

SVN(Subversion)是一款版本管理工具,把数据放置在一个中央资料档案(repository) 中。 这个档案库很像一个普通的文件服务器, 用户可以从这个服务器上下载和上传文件,不过它还会记住每一次文件的变动。 这样你就可以把档案恢复到旧的版本, 或是浏览文件的变动历史。

SVN 分会为两个部分,服务器部分和客户端部分,服务器部分的操作主要是由配置管理员完成,包括 SVN 服务器环境的搭建、版本库的创建、用户的创建与权限分配以及版本库数据的定期备份

这里补充一下 “检出” 操作:Checkout 操作是用来从版本库创建一个工作副本。工作副本是开发者私人的工作空间,可以进行内容的修改,然后提交到版本库中。

服务端的搭建

SVN 安装环境

SVN 和 Git 不同,它是需要一个中央服务器

输入 svn 命令检查是否安装了

安装 svn

sudo apt-get install subversion

# sudo mkdir /home/svn
# 这里也可以直接创建一个 svn 用户,让它进入 sudo 组,方便管理
su root
useradd mysvn -m -G sudo -c "svn manager user" -s /bin/bash
# sudo echo "password" | passwd --stdin svn
echo mysvn:123456 | chpasswd

# 检查是否安装成功
svn --version

服务端创建项目


su mysvn
cd /home/mysvn

# 创建项目仓库目录,在 SVN 根目录下创建一个新文件夹,作为项目仓库
mkdir /home/mysvn/rep

使用 svn 命令创建 SVN 文件仓库

svnadmin create /home/mysvn/rep

然后这个目录下会出现以下文件

SVN 配置文件

在这个项目里面 conf 下的 svnserve.confpasswdauthz 这三个文件是用来配置当前项目的,主要包括用户名,密码,权限等

配置用户名密码

vim passwd

先来配置最简单的用户名和密码,在 passwd 中 [users] 下面,根据注释的样子配置,等于号前面的是用户名后面的是密码,用户名前不要空格,等于号两遍有空格

配置分组权限

版本库路径权限段的段名格式如下:

[<版本库名>:<路径>] 

如下:

[groups]
g_admin = admin,thinker

[admintools:/]
@g_admin = rw
* =

[test:/home/thinker]
thinker = rw
* = r
vim authz

在 authz 中 [groups] 下面,配置一个叫做 develop 的分组,里面有两个用户 mysvn 和 alsritter,[/] 表示所有的目录,@ 后面跟的是组名,这里是 @develop 等于号右边的 rw 表示读写权限都有

服务配置文件

svn 服务配置文件为版本库目录中的文件 conf/svnserve.conf,该文件仅由一个 [general] 配置段组成。

anon-access:控制非鉴权用户访问版本库的权限,取值范围为 "write"、"read"和"none"。 即 "write" 为可读可写,"read" 为只读,"none" 表示无访问权限。 默认值:read

auth-access:控制鉴权用户访问版本库的权限。取值范围为"write"、"read"和"none"。 即"write"为可读可写,"read"为只读,"none"表示无访问权限。 默认值:write

authz-db:指定权限配置文件名,通过该文件可以实现以路径为基础的访问控制。 除非指定绝对路径,否则文件位置为相对conf目录的相对路径。 默认值:authz

realm:指定版本库的认证域,即在登录时提示的认证域名称。若两个版本库的 认证域相同,建议使用相同的用户名口令数据文件。 默认值:一个UUID(Universal Unique IDentifier,全局唯一标示)。

下面介绍几个主要的配置示例:

配置 svnserve.conf 文件,将

anon-access = none
auth-access = write

前面的 # 和空格去掉,第一行表示匿名用户的权限,配置的是无(默认是 read),第二行表示认证用户的权限,我配置的是写

password-db = passwd

前面的 # 和空格去掉,表示使用用户名密码

authz-db = authz

前面的 # 和空格去掉,表示使用权限认证

启动 SVN 服务

svnserve -d -r /home/mysvn/rep
# svnserve -d -r 目录 --listen-port 端口号
  • -r:配置方式决定了版本库访问方式。
  • --listen-port:指定SVN监听端口,不加此参数,SVN默认监听3690

由于 -r 配置方式的不一样,SVN 启动就可以有两种不同的访问方式

方式一:-r 直接指定到版本库(称之为单库 svnserve 方式)

svnserve -d -r /home/mysvn/rep

在这种情况下,一个 svnserve 只能为一个版本库工作。

authz 配置文件中对版本库权限的配置应这样写:

[groups]
admin=user1
dev=user2

[/]
@admin=rw
user2=r

使用类似这样的 URL:svn://192.168.211.129/ 即可访问 rep 版本库

方式二:指定到版本库的上级目录(称之为多库 svnserve 方式)

svnserve -d -r /home/mysvn

这种情况,一个 svnserve 可以为多个版本库工作

authz 配置文件中对版本库权限的配置应这样写:

[groups]
admin=user1
dev=user2

[project01:/]
@admin=rw
user2=r

[project01:/]
@admin=rw
user2=r

如果此时你还用 [/],则表示所有库的根目录,同理,[/src] 表示所有库的根目录下的 src 目录。

使用类似这样的 URL:svn://192.168.211.129/project01 即可访问 project01 版本库。

SVN 客户端操作

SVN 检出操作

因为使用的是单库 svnserve 方式,所以无需指定地址

svn checkout svn://192.168.211.129/ --username=alsritter

status 状态

# 查看或目录状态

svn status

svn st

# 显示文件及子目录的状态,正常不显示

# ? 不在svn的控制中

# M 内容被修改

# C 发生冲突

# A 预订加入到版本库

# K 被锁定

add 添加

# 向版本库添加新文件

svn add a.txt

svn add *.txt

# 递归添加文件夹下所有内容

svn add b

# 已经添加的文件修改后无法添加,只能用commit

例如在本地库中增加一个 readme 的说明文件。

查看工作副本状态:

svn status

此时 readme 的状态为?,说明它还未加到版本控制中。

将文件 readme 加到版本控制,等待提交到版本库。

svn add readme 

commit 提交

svn commit -m '注释内容' [-N] [--no-unlock] PATH

# 提交文件

svn commit -m 'add a.txt' a.txt

# 提交文件夹

svn commit -m 'add b' b

# 简写

svn ci

上面那节中添加文件后

此时 readme 的状态为A,它意味着这个文件已经被成功地添加到了版本控制中。

为了把 readme 存储到版本库中,使用 commit -m 加上注释信息来提交。

svn commit -m "SVN readme."

出现以下报错:

出现这种问题的原因在于搭建 SVN 服务器,包括创建 Repository 目录 /home/svn 目录下的一切子目录和文件都是在 root 用户下进行的,所以在 root 用户下检出、提交都没有问题。而如果使用其它用户提交则有问题

解决办法: 在服务器上把 Users 对 Repository 的完全控制权限加上就可以了,执行如下命令对 /home/svn 目录下的所有文件和子目录添加 Users 的读写权限

sudo chmod -R o+rw /home/mysvn

再次提交就畅通无阻了

update 更新

# 更新到最新版本

svn update

# 只更新某个特定文件

svn update a.txt

# 还原到指定版本

svn update -r 1

# 还原某个文件到指定版本

svn update -r 1 c.txt

# 简写

svn up

lock 锁

执行了 svn lock 命令,可以防止其他人进行提交。直到执行了锁定的用户执行了解锁命令

svn lock -m '加锁注释内容' [--force] PATH

# 加锁

svn lock -m "锁定文件" a.txt

# 解锁

svn unlock a.txt

delete 删除

# 删除版本库中文件

svn delete svn://127.0.0.1/demo/c.txt -m 'delete c.txt'

# 然后执行更新

svn update

# 推荐使用

svn delete c.txt

svn commit -m 'delete c.txt'

# 简写

svn (del, remove, rm)

revert 版本回退

当我们想放弃对文件的修改,可以使用 SVN revert 命令。

svn revert 操作将撤销任何文件或目录里的局部更改。

我们对文件 readme 进行修改,查看文件状态。

svn status
# 这时我们发现修改错误,要撤销修改,通过 svn revert 文件 readme 回归到未修改状态。
svn revert readme

进行 revert 操作之后,readme 文件恢复了原始的状态。 revert 操作不单单可以使单个文件恢复原状, 而且可以使整个目录恢复原状。恢复目录用 -R 命令,如下。

svn revert -R trunk

但是,假如我们想恢复一个已经提交的版本怎么办。

为了消除一个旧版本,我们必须撤销旧版本里的所有更改然后提交一个新版本。这种操作叫做 reverse merge

首先,找到仓库的当前版本,现在是版本 22,我们要撤销回之前的版本,比如版本 21。

svn merge -r 22:21 readme 

diff 比较差异

# 比较当前修改和版本库中的差异

svn diff c.txt

# 版本之间对比

svn diff -r 1:2 a.txt

# 简写

svn di

merge 合并


# 将3版本和4版本合并到当前文件
svn merge -r 3:4 c.txt

# 但是一般都会产生冲突,需要处理一下

安装客户端

到官网下载这个 TortoiseSVN

安装好后:

新建本地仓库

本地仓库对应远程仓库即 SVN 服务器,本地仓库就是用于存放各种文档、程序的一个文件夹,在自己或别人编辑完后可通过 SVN 更新操作把最新版本的文件下载到本地仓库,或者通过 SVN 提交操作把自己的更改推送到服务器以方便他人获取

右键创建项目,输入远程仓库地址以绑定 SVN 服务器

svn://192.168.211.129/

输入用户名称密码后就拉取下来了

修改提交:

然后在弹出的界面中输入这次提交的备注信息

再在其它的客户端 Update 就能看到更新的信息了

测试冲突解决

这里在 Linux 的测试提交

在 Window 客户端上测试提交

然后显示冲突了

正确的做法是,点击这个 readme 文件,使用 TortoiseSVN 菜单里的【Edit conflicts】这个功能,编辑冲突。

工具自带的一个编辑窗口,主要分为三个部分,左上是指冲突的版本 12 文件的内容,右上是我们本地副本的内容(就是刚修改了,未提交的文件),最下面,是处理冲突合并后的效果。

这里提示的就是它们两个冲突,工具不知道如何自动合并,只能人工处理。我们最后修改的内容为【0000】,我们在右上的窗口这一行上面点击右键,选择【使用此块】,下面的合并窗口内容第一行,就会变为绿色(原来是红色的一行问号),如此类推,两边进行选择正确的代码就可以,重要的是【Merged】的窗口里的内容是我们想要的,就可以。

最后都处理完,下图上方红圆圈的地方【Maker as resolved】点击它,完成合并冲突。

此时,目录中的多余文件消失掉

再看下 readme 的内容,就是我们刚合并的内容,好了,冲突合并的解决流程就演示完成,下一步就可以提交文件,又回到基本的操作上。

SVN 查看历史信息

通过 svn 命令可以根据时间或修订号去除过去的版本,或者某一版本所做的具体的修改。以下四个命令可以用来查看svn 的历史:

  • svn log:用来展示 svn 的版本作者、日期、路径等等。
  • svn diff:用来显示特定修改的行级详细信息。
  • svn cat:取得在特定版本的某文件显示在当前屏幕。
  • svn list:显示一个目录或某一版本存在的文件。

log 日志

# 显示这个文件的修改记录,及版本号的变化(也可以直接显示全部文件变化)
svn log a.txt

如果只希望查看特定的某两个版本之间的信息,可以使用:

svn log -r 2:4

如果希望得到目录的信息要加 -v。 如果希望显示限定 N 条记录的目录信息,使用 svn log -l N -v

svn log -l 5 -v 

svn list

svn list 可以在不下载文件到本地目录的情况下来察看目录中的文件:

svn list http://192.168.0.1/

SVN 分支

在 SVN 上分支的概念比较弱,它没有专门的分支管理,都是自己维护分支的:

SVN 默认管理目录如下(自己手动创建):

通常 branches 目录下为开发分支,tags 目录为标签目录,trunk 为主目录。一般在开发目录下创建分支进行功能开发,开发完成并经过测试无bug,再合并到 trunk 目录。在合并之前应当先把当前 trunk 打一个 tag 作为备份。

我们在本地副本中创建一个 my_branch 分支。

# 在本地副本中创建一个 my_branch 分支
svn copy trunk/ branches/my_branch

提交新增的分支到版本库。

svn commit -m "add my_branch"

接着我们就到 my_branch 分支进行开发,切换到分支路径并创建 index.html 文件。

cd branches/my_branch/

index.html 加入版本控制,并提交到版本库中。

svn status
svn add index.html
svn commit -m "add index.html"

切换到 trunk,执行 svn update,然后将 my_branch 分支合并到 trunk 中。

svn merge ../branches/my_branch/

此时查看目录,可以看到 trunk 中已经多了 my_branch 分支创建的 index.html 文件。

将合并好的 trunk 提交到版本库中。

svn commit -m "add index.html"

SVN 标签(tag)

同上分支,这个版本管理也是自己手动维护的

svn copy trunk/ tags/v1.0
ls tags/
ls tags/v1.0/
# 查看状态
svn status
# 提交tag内容。
svn commit -m "tags v1.0"